package yang.itcode.service.impl;

import cn.hutool.json.JSONObject;
import com.github.pagehelper.PageHelper;
import com.github.pagehelper.PageInfo;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;
import yang.itcode.exception.BusinessException;
import yang.itcode.mapper.InventoryDetailMapper;
import yang.itcode.mapper.ProductMapper;
import yang.itcode.mapper.ProfitMapper;
import yang.itcode.model.pojo.Category;
import yang.itcode.model.pojo.InventoryDetail;
import yang.itcode.model.pojo.Product;
import yang.itcode.model.pojo.Profit;
import yang.itcode.service.CategoryService;
import yang.itcode.service.InventoryDetailService;
import yang.itcode.utils.ThreadUtil;

import java.math.BigDecimal;
import java.time.LocalDate;
import java.time.format.DateTimeFormatter;
import java.util.ArrayList;
import java.util.List;

import static yang.itcode.constant.ErrorConstant.*;
import static yang.itcode.constant.OptionConstant.*;

@Service
public class InventoryDetailServiceImpl implements InventoryDetailService {

    @Autowired
    private InventoryDetailMapper inventoryDetailMapper;
    @Autowired
    private ProfitMapper profitMapper;
    @Autowired
    private ProductMapper productMapper;
    @Autowired
    private CategoryService categoryService;

    @Override
    @Transactional
    public boolean createInventoryDetail(JSONObject obj) {
        Integer userId = ThreadUtil.getCurrentId();
        Integer productId = obj.getInt("productId");
        LocalDate date = LocalDate.parse(obj.getStr("date"));
        BigDecimal quantity = obj.getBigDecimal("quantity");
        BigDecimal currentAvgCost = obj.getBigDecimal("currentAvgCost");
        BigDecimal balanceQuantity = obj.getBigDecimal("balanceQuantity");
        String opreation = obj.getStr("operation");
        String note = obj.getStr("note");
        JSONObject condition = new JSONObject();
        condition.set("productId", productId);
        condition.set("status", 1);
        condition.set("orderBy", "create_time");
        condition.set("sortOrder", "desc");
        PageHelper.startPage(1, 1);
        List<InventoryDetail> list = inventoryDetailMapper.selectByCondition(condition);
        InventoryDetail lastRecord = list.isEmpty() ? null : list.get(0);
        if (lastRecord == null) {
            lastRecord.setBalanceQuantity(BigDecimal.ZERO);
        }
        if (productId == null || quantity == null || opreation == null) {
            throw new BusinessException(INVENTORY_DETAIL_PARAM_EXCEPTION_CODE, INVENTORY_DETAIL_PARAM_EXCEPTION_MESSAGE);
        }
        if ("damage".equals(opreation) && lastRecord.getBalanceQuantity().compareTo(quantity) < 0) {
            throw new BusinessException(INVENTORY_DETAIL_PARAM_EXCEPTION_CODE, INVENTORY_DETAIL_NOT_ENOUGH_EXCEPTION_MESSAGE);
        }
        InventoryDetail inventoryDetail = new InventoryDetail();
        inventoryDetail.setProductId(productId);
        inventoryDetail.setDate(date);
        if ("damage".equals(opreation)) {
            inventoryDetail.setOperationType(INVENTORY_OPTION_DAMAGE);
            inventoryDetail.setQuantity(quantity.negate());
            inventoryDetail.setBalanceQuantity(lastRecord.getBalanceQuantity().subtract(quantity));
        } else if ("overflow".equals(opreation)) {
            inventoryDetail.setOperationType(INVENTORY_OPTION_OVERFLOW);
            inventoryDetail.setQuantity(quantity);
            inventoryDetail.setBalanceQuantity(lastRecord.getBalanceQuantity().add(quantity));
        } else {
            return false;
        }
        inventoryDetail.setCurrentAvgCost(lastRecord.getCurrentAvgCost());
        inventoryDetail.setBalanceValue(lastRecord.getBalanceValue());
        inventoryDetail.setNote(note);
        inventoryDetail.setCreateUserId(userId);
        inventoryDetail.setUpdateUserId(userId);
        if (inventoryDetailMapper.insert(inventoryDetail) != 1) {
            throw new BusinessException(INVENTORY_DETAIL_ADD_EXCEPTION_CODE, INVENTORY_DETAIL_ADD_EXCEPTION_MESSAGE);
        }
        // 查询最新的报损或报溢记录
        condition = new JSONObject();
        condition.set("productId", productId);
        condition.set("productId", productId);
        condition.set("status", 1);
        condition.set("orderBy", "create_time");
        condition.set("sortOrder", "desc");
        PageHelper.startPage(1, 1);
        list = inventoryDetailMapper.selectByCondition(condition);
        lastRecord = list.isEmpty() ? null : list.get(0);
        Profit profit = new Profit();
        BigDecimal value = lastRecord.getQuantity().multiply(lastRecord.getCurrentAvgCost());
        if ("damage".equals(opreation)) {
            profit.setOperationType(PROFIT_OPTION_DAMAGE);
            profit.setValue(value);
            profit.setNote("报损，损失金额：" + value);
        } else {
            profit.setOperationType(PROFIT_OPTION_OVERFLOW);
            profit.setValue(value);
            profit.setNote("报溢，增加金额：" + value);
        }
        profit.setDate(date);
        profit.setRelatedId(lastRecord.getId());
        profit.setCreateUserId(userId);
        profit.setUpdateUserId(userId);
        return profitMapper.insert(profit) == 1;
    }

    @Override
    public PageInfo<JSONObject> getInventoryDetailList(Integer pageNum, Integer pageSize, JSONObject condition) {
        PageHelper.startPage(pageNum, pageSize);
        if (condition.getInt("categoryId") != null) {
            List<Category> categories = categoryService.getCategoryWithDescendants(condition.getInt("categoryId"));
            List<Integer> categoryIds = categories.stream().map(Category::getId).toList();
            condition.remove("categoryId");
            condition.set("categoryIds", categoryIds);
        }
        List<String> operationTypes = new ArrayList<>();
        operationTypes.add(INVENTORY_OPTION_PURCHASE);
        operationTypes.add(INVENTORY_OPTION_SALES);
        operationTypes.add(INVENTORY_OPTION_OVERFLOW);
        operationTypes.add(INVENTORY_OPTION_DAMAGE);
        operationTypes.add(INVENTORY_OPTION_RED_PURCHASE);
        operationTypes.add(INVENTORY_OPTION_RED_SALES);
        operationTypes.add(INVENTORY_OPTION_OTHER);
        condition.set("operationTypes", operationTypes);
        condition.set("status", 1);
        List<JSONObject> list = inventoryDetailMapper.selectInventoryDetailView(condition);
        return new PageInfo<>(list);
    }

    @Override
    public JSONObject getInventoryDetailChangeList(JSONObject obj) {
        Product product = productMapper.selectById(obj.getInt("productId"));
        if (product == null) {
            throw new BusinessException(PRODUCT_NOT_EXIST_EXCEPTION_CODE, PRODUCT_NOT_EXIST_EXCEPTION_MESSAGE);
        }
        obj.set("unit", product.getUnit());
        if ("year".equals(obj.getStr("mode"))){
            LocalDate startDate = obj.get("startDate", LocalDate.class);
            LocalDate endDate = obj.get("endDate", LocalDate.class);
            JSONObject yearRange = obj.getJSONObject("yearRange");
            int startYear = yearRange.getInt("start");
            int endYear = yearRange.getInt("end");
            DateTimeFormatter formatter = DateTimeFormatter.ofPattern("yyyy-MM-dd HH:mm:ss");
            List<JSONObject> list = new ArrayList<>();
            JSONObject condition = new JSONObject();
            condition.set("productId", product.getId());
            condition.set("startDate", startDate);
            condition.set("endDate", endDate);
            condition.set("status", 1);
            condition.set("orderBy", "create_time");
            condition.set("sortOrder", "asc");
            List<String> operationTypes = new ArrayList<>();
            operationTypes.add(INVENTORY_OPTION_PURCHASE);
            operationTypes.add(INVENTORY_OPTION_SALES);
            operationTypes.add(INVENTORY_OPTION_OVERFLOW);
            operationTypes.add(INVENTORY_OPTION_DAMAGE);
            operationTypes.add(INVENTORY_OPTION_RED_PURCHASE);
            operationTypes.add(INVENTORY_OPTION_RED_SALES);
            operationTypes.add(INVENTORY_OPTION_OTHER);
            condition.set("operationTypes", operationTypes);
            List<InventoryDetail> inventoryDetails = inventoryDetailMapper.selectByCondition(condition);
            for (InventoryDetail detail : inventoryDetails) {
                JSONObject item = new JSONObject();
                item.set("time", detail.getCreateTime().format(formatter));
                item.set("quantity", detail.getBalanceQuantity());
                item.set("change", detail.getQuantity());
                item.set("operationType", detail.getOperationType());
                list.add(item);
            }
            obj.set("list", list);
            return obj;
        } else if ("month".equals(obj.getStr("mode"))) {
            LocalDate startDate = obj.get("startDate", LocalDate.class);
            LocalDate endDate = obj.get("endDate", LocalDate.class);
            JSONObject monthRange = obj.getJSONObject("monthRange");
            // 解析范围的YYYY-MM格式字符串
            String startMonthStr = monthRange.getStr("start");
            String endMonthStr = monthRange.getStr("end");
            String[] startParts = startMonthStr.split("-");
            String[] endParts = endMonthStr.split("-");
            int startYear = Integer.parseInt(startParts[0]);
            int startMonth = Integer.parseInt(startParts[1]);
            int endYear = Integer.parseInt(endParts[0]);
            int endMonth = Integer.parseInt(endParts[1]);
            DateTimeFormatter formatter = DateTimeFormatter.ofPattern("yyyy-MM-dd HH:mm:ss");
            List<JSONObject> list = new ArrayList<>();
            JSONObject condition = new JSONObject();
            condition.set("productId", product.getId());
            condition.set("startDate", startDate);
            condition.set("endDate", endDate);
            condition.set("status", 1);
            condition.set("orderBy", "create_time");
            condition.set("sortOrder", "asc");
            List<String> operationTypes = new ArrayList<>();
            operationTypes.add(INVENTORY_OPTION_PURCHASE);
            operationTypes.add(INVENTORY_OPTION_SALES);
            operationTypes.add(INVENTORY_OPTION_OVERFLOW);
            operationTypes.add(INVENTORY_OPTION_DAMAGE);
            operationTypes.add(INVENTORY_OPTION_RED_PURCHASE);
            operationTypes.add(INVENTORY_OPTION_RED_SALES);
            operationTypes.add(INVENTORY_OPTION_OTHER);
            condition.set("operationTypes", operationTypes);
            List<InventoryDetail> inventoryDetails = inventoryDetailMapper.selectByCondition(condition);
            for (InventoryDetail detail : inventoryDetails) {
                JSONObject item = new JSONObject();
                item.set("time", detail.getCreateTime().format(formatter));
                item.set("quantity", detail.getBalanceQuantity());
                item.set("change", detail.getQuantity());
                item.set("operationType", detail.getOperationType());
                list.add(item);
            }
            obj.set("list", list);
            return obj;
        } else if ("day".equals(obj.getStr("mode"))){
            LocalDate startDate = obj.get("startDate", LocalDate.class);
            LocalDate endDate = obj.get("endDate", LocalDate.class);
            DateTimeFormatter formatter = DateTimeFormatter.ofPattern("yyyy-MM-dd HH:mm:ss");
            List<JSONObject> list = new ArrayList<>();
            JSONObject condition = new JSONObject();
            condition.set("productId", product.getId());
            condition.set("startDate", startDate);
            condition.set("endDate", endDate);
            condition.set("status", 1);
            condition.set("orderBy", "create_time");
            condition.set("sortOrder", "asc");
            List<String> operationTypes = new ArrayList<>();
            operationTypes.add(INVENTORY_OPTION_PURCHASE);
            operationTypes.add(INVENTORY_OPTION_SALES);
            operationTypes.add(INVENTORY_OPTION_OVERFLOW);
            operationTypes.add(INVENTORY_OPTION_DAMAGE);
            operationTypes.add(INVENTORY_OPTION_RED_PURCHASE);
            operationTypes.add(INVENTORY_OPTION_RED_SALES);
            operationTypes.add(INVENTORY_OPTION_OTHER);
            condition.set("operationTypes", operationTypes);
            List<InventoryDetail> inventoryDetails = inventoryDetailMapper.selectByCondition(condition);
            for (InventoryDetail detail : inventoryDetails) {
                JSONObject item = new JSONObject();
                item.set("time", detail.getCreateTime().format(formatter));
                item.set("quantity", detail.getBalanceQuantity());
                item.set("change", detail.getQuantity());
                item.set("operationType", detail.getOperationType());
                list.add(item);
            }
            obj.set("list", list);
            return obj;
        }
        return null;
    }
}
